
/*-----------------------------------------------File Info------------------------------------------------
** File Name:               Protocol.c  
** Last modified date:      2016.07.22
** Last version:            V0.1
** Description:             
**--------------------------------------------------------------------------------------------------------            
** Created date:            2016.09.07
** author:                  YLY
** Version:                 V0.1
** Descriptions:            任务1 
**--------------------------------------------------------------------------------------------------------
*/
/*************************************************************
* 	include 
* 	头文件	
*************************************************************/ 
#include "loadMain.h"
#include "loadProtocol.h"
#include "arithmetic.h"
#include "bootloader.h"
#include "appGpio.h"

uint8_t gProTaskId;
static tsProRece gtProRece, gtProReceApp;
static uint8_t gProSendBuf[PRO_SEND_BUF_SIZE];
volatile bool sentFinish = true;
tsCfgI2c gProI2c = PRO_I2C;

static void proSendCallback(teFeedback eFeedback, uint8_t *pData, uint16_t size)
{
	sentFinish = true;
	gpioWrite(&gtCfgIntOut,1);
}

static void proReceCallback(teFeedback eFeedback, uint8_t *pData, uint16_t size)
{
	if(eFeedback == I2C_SUCCESS && pData != NULL && size > 0)
	{		
		if(gtProReceApp.len == 0)
		{
			gtProReceApp.len = size;
			memcpy(gtProReceApp.data, pData, size);	
		}
	}
}

//---------协议打包----------
bool protocolPackage(uint8_t cmd, uint8_t *pData, uint16_t dataLen)
{
	uint8_t i = 0;
	uint8_t regain;
	tsProtocol *pProSend = (tsProtocol *)gProSendBuf;
	uint16_t len;	/* buf大小 */
	
	if(cmd == 0x00)
		return false;

	memset((uint8_t *)gProSendBuf,0x00,sizeof(gProSendBuf));
	
	len = dataLen+4;
	

	/* 协议封装 */
	pProSend->cmd = cmd;
	memcpy(pProSend->data,pData,dataLen);
	pProSend->len[0] = (uint8_t)((dataLen+2)>>8);	//外面只传数据字节长度，数据长度＝数据N+协议类型1+检验位1
	pProSend->len[1] = (uint8_t)(dataLen+2);		//外面只传数据字节长度，数据长度＝数据N+协议类型1+检验位1
	pProSend->check = ucBufCheckXor((uint8_t *)(&pProSend->cmd),dataLen+1);	//异或校验，长度＝协议类型1+数据（无校验位）
	sentFinish = false;
	
	GLOBAL_DBG("proWr,cmd=0x%x,len=%d\r\n",cmd,len);	
	/* 发送数据 */
	i2cSlaveWrite(&gProI2c, (uint8_t *)pProSend, len, proSendCallback);	//发送数据，长度＝数据长度2+协议类型1+数据+校验1	
	
	gpioWrite(&gtCfgIntOut,0);
	while(sentFinish == false)	//判断是否发送结束
	{
		for(i = 0; i<0xff; i++)
			__NOP();
	}
	return true;
}
void requestStartUpdata(void)
{
	uint8_t buf[8];

	buf[0] = 0;
	protocolPackage(UPDATE_DATA_REQUEST,buf,1);	
	GLOBAL_DBG("requestStartUpdata\r\n");
}
					

void answer(bool sta)
{
	uint8_t buf[8];

	if(sta)
		buf[0] = MASTER_SUCCESS;
	else	
		buf[0] = MASTER_FAIL;
	protocolPackage(ANSWER_MASTER,buf,1);	 
}

extern void setWorkSta(teStatus status);
bool protocolProcessing(void)
{
	/* 数据流 */
	static uint8_t  updateBuf[FMC_PAGE_SIZE];	//升级数据缓存
	static uint32_t updateSize=0;				//升级数据大小	
	static uint16_t hasReceivedPackNum = 0;		//已经接收的包号.
	static uint16_t updataPackNum = 0;			//升级包号		
	tsUserData	*ptUserData = (tsUserData	*)USER_DATA_ADDR;
	
	uint16_t recvPackNum = 0;					//包号
	uint16_t dataLen=0;							//有效数据长度
	uint32_t address;
	
	/* 通讯 */	
	uint8_t buf[32];					//临时缓冲区
	uint16_t len;						//数据长度
	tsProtocol	*ptPro;					//协议结构体
	
	/* 其它 */
	uint8_t packageCheckSum;
	uint16_t i;
	
	if(gtProReceApp.len)
	{
		do
		{
			ptPro = (tsProtocol *)gtProReceApp.data;
			len = ((uint16_t)ptPro->len[0] << 8) | ((uint16_t)ptPro->len[1]);				//保存数据长度
			
			if((len == 0)||(len > gtProReceApp.len))		//预防接收到数据错误，造成指针指向错误地址，单片机重启
			{
				return false;
			}
			if(ptPro->check != ucBufCheckXor((uint8_t *)(&ptPro->cmd),len-1))		//数据校验，去掉校验位
			{
				return false;
			}	

			if(ptPro->check == ucBufCheckXor((uint8_t *)(& ptPro->cmd),len-1))		//数据校验，去掉校验位
			{
				switch(ptPro->cmd)
				{		
					case GET_PROGRAM_VER:	//0x97获取软件信息
					{
						answer(true);//主机发送数据，从机必需进行一次应答
				
						buf[0] = MCU_TYPE;							//单片机型号
						buf[1] = ptUserData->apromVerArch;			//AP程序版本号
						buf[2] = ptUserData->apromVerSoft;			//AP程序版本号
						buf[3] = ptUserData->apromVerModify;		//AP程序版本号
						buf[4] = RUNNING_ENV_LDROM;					//当前程序运行环境（0x02 LDROM）
						buf[5] = ptUserData->model;					//AP程序代码
						buf[6] = ptUserData->companyH;				//AP厂商代码高位
						buf[7] = ptUserData->companyL;				//AP厂商代码低位			
						protocolPackage(RESPONSE_PRO_VER,buf,8);					
					}break;
					
					
					case START_UPDATE_PRO:				//0x98启动软件升级
					{
						GLOBAL_ERR("\n,START_UPDATE!!!");
						updataPackNum = 0;
						hasReceivedPackNum = 0;		//重置包号
						answer(true);	//主机发送数据，从机必需进行一次应答
					}break;
									
					case UPDATE_DATA:	//0x99 升级数据流传输
					{					
						recvPackNum = (ptPro->data[0] << 8) | (ptPro->data[1]);	//获取包号
						GLOBAL_DBG("\npkN=%d",recvPackNum);
						if((recvPackNum != hasReceivedPackNum) \
							&&	(0 != recvPackNum))					//传输的包号不对且不是重新开始传，回复失败
						{
							GLOBAL_ERR("\n,packNumErr!!!");
							answer(false);
							break;
						}
						if(0 == recvPackNum)		//重新开始传输
						{
							memset(updateBuf,0xff,sizeof(updateBuf));
							updateSize = 0;
							hasReceivedPackNum = 0;
							updataPackNum = 0;
						}
						
						/*  */
						dataLen = len - 5;	//有效数据长度
						packageCheckSum = ucBufCheckSum(ptPro->data+2,dataLen);
						if(packageCheckSum != ptPro->data[len-3])		//包校验通过
						{
							updateSize = 0;
							hasReceivedPackNum = 0;
							updataPackNum = 0;
							GLOBAL_ERR("\n,checkSumERR!!");
							answer(false);
							break;
						}						

						//复制数据
						memcpy(updateBuf+updateSize, ptPro->data+2, dataLen);
						hasReceivedPackNum++;
						updateSize += dataLen;				
						if(dataLen != 512)	//单包数据最大512，最后一包不能为512
						{	
							address = APP_FLASH_BASE + updataPackNum*FMC_PAGE_SIZE;
							updataPackNum++;														
							fmcErasePages(address, 1);	//擦除FLASH
							fmcProgram(address, updateBuf, updateSize);		//将接收到的数据写入flash							
							setWorkSta(ISP_UPDATEING);	//升级中
							memset(updateBuf,0xff,sizeof(updateBuf));							
							updateSize = 0;	
						}
						else	//非最后一包数据
						{	
							if(updateSize == FMC_PAGE_SIZE)	//接收数据满一个块，写入FLASH
							{
								address = APP_FLASH_BASE + updataPackNum*FMC_PAGE_SIZE;
								updataPackNum++;								
								fmcErasePages(address, 1);	//擦除FLASH
								fmcProgram(address, updateBuf, updateSize);		//将接收到的数据写入flash	
								
								setWorkSta(ISP_UPDATEING);	//升级中
								updateSize = 0;	
								memset(updateBuf,0xff,sizeof(updateBuf));
							}
						}
						answer(true);							
					}break;
					
					case UPDATE_FINISH:	//0x9A 升级结束
					{
						answer(true);
						setWorkSta(ISP_FINISH);			//升级结束
						if(ptPro->data[0] == 0x00)		//升级正常结束，切换到APROM
						{
							jumpToApplication();
							/* 运行到此处说明跳转失败，重启MCU或跳转到bootloader */
							jumpToBootloader();
						}							
					}break;
					default:
						break;
				}
				gtProReceApp.len = 0;	//清除数据长度便于下次接收
				return true;				
			}	
			else
			{
				answer(false);														
			}
		}while(0);
		gtProReceApp.len = 0;	//清除数据长度便于下次接收
	}
	return false;
}

void protocolInit(void)
{
	gpioWrite(&gtCfgIntOut,1);
	i2cInit(&gProI2c, PRO_CLK_RATE, PRO_I2C_SLAVE_ADDR0);			/* I2C初始化 */
	i2cSlaveRead(&gProI2c, gtProRece.data, sizeof(gtProRece.data), proReceCallback);	/* 使能接收 */
}




